﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace jogoLudumdare
{
    class Fase3 : State
    {
        private const int WIDTH = 800; //Atributo que irá defenir a largura da janela do jogo em 800 pixels.
        private const int HEIGHT = 600; //Atributo que irá definir a autura da janela do jogo em 600 pixels.

        private enum StageState //Estados possíveis de jogo.
        {
            gameplay,
            pause,
            youwin,
            youlose
        }
        private StageState stageState; //Estado atual de jogo.

        private Background background; //Instanciamos o plano de fundo "background".
        private Plataform colisionPlataform; //Instanciamos a plataforma que usaremos na colisão.
        private Plataform maskPlataform; //Instanciamos a plataforma que usaremos para interface.
        private Character cleber; //Instanciamos o personagem "Cleber".
        private Bullet bullet; //Instanciamos o projetil "bullet".
        private Enemy vilao; //Instanciamos o inimigo "vilao".
        private Icon cleberAvatar; //Icone de avatar do personagem.
        private Icon vilaoAvatar; //Icone de avatar do inimigo.
        private Icon cleberLifeBar; //Barra de vida do personagem.
        private Icon vilaoLifeBar; //Barra de vida do inimigo.
        private Background pauseScreen; //Tela de pause.
        private Background winScreen; //Tela de vitoria.
        private Background loseScreen; //Tela de derrota.

        private KeyboardState keyNow; //Armazena a tecla usada pelo usuário no momento.
        private KeyboardState keyBefore; //Armazena a tecla usada pelo usuário anteriormente.

        public Fase3(ContentManager content)
        {
            this.stageState = StageState.gameplay;
            //Carregamos o personagem e definimos os parâmetros necessários.
            cleber = new Character(content.Load<Texture2D>(@"Fase3\cleber"), new Rectangle(0, 300, 80, 100),
                new Rectangle(0, 0, 180, 220), new Vector2(6, 28), 5, 100);
            //Carregamos o bullet e definimos os parâmetros necessários.
            bullet = new Bullet(content.Load<Texture2D>(@"Fase3\projetil"), new Rectangle(0, 0, 70, 25));
            //Carregamos o inimigo e definimos os parâmetros necessários.
            vilao = new Enemy(content.Load<Texture2D>(@"Fase3\vilao"), new Rectangle(400, 300, 80, 100),
                new Rectangle(0, 0, 180, 220), new Vector2(6, 28), 5, 100);
            //Carregamos o avatar e definimos os parâmetros necessários.
            cleberAvatar = new Icon(content.Load<Texture2D>(@"Fase3\cleberIcon"), new Rectangle(5, 0, 40, 45));
            //Carregamos o avatar e definimos os parâmetros necessários.
            vilaoAvatar = new Icon(content.Load<Texture2D>(@"Fase3\vilaoIcon"), new Rectangle(755, 0, 40, 40));
            //Carregamos a barra de vida e definimos os parâmetros necessários.
            cleberLifeBar = new Icon(content.Load<Texture2D>(@"Fase3\LifeBar"), new Rectangle(50, 25, 200, 10));
            //Careggamos a barra de vida e definimos os parâmetros necessários.
            vilaoLifeBar = new Icon(content.Load<Texture2D>(@"Fase3\LifeBar"), new Rectangle(550, 25, 200, 10));
            //Carregamos o background e definimos os parâmetros necessários.
            background = new Background(content.Load<Texture2D>(@"Fase3\background"), new Rectangle(0, 0, 800, 600));
            //Carregamos a plataforma e definimos os parâmetros necessários.
            colisionPlataform = new Plataform(content.Load<Texture2D>(@"Fase3\plataforma"), new Rectangle(0, 550, 800, 50));
            //Carregamos a plataforma e definimos os parâmetros necessários.
            maskPlataform = new Plataform(content.Load<Texture2D>(@"Fase3\chao"), new Rectangle(-250, 220, 1300, 600));
            //Carregamos a tela de pause e definimos os parâmetros necessários.
            pauseScreen = new Background(content.Load<Texture2D>(@"Fase3\ScreenPause"), new Rectangle(0, 0, 800, 600));
            //Carregamos a tela de vitoria e definimos os parâmetros necessários.
            winScreen = new Background(content.Load<Texture2D>(@"Fase3\ScreenYouWin"), new Rectangle(0, 0, 800, 600));
            //Carregamos a tea de derrota e definimos os parâmetros necessários.
            loseScreen = new Background(content.Load<Texture2D>(@"Fase3\ScreenYouLose"), new Rectangle(0, 0, 800, 600));
        }
        
        public void Update(GameTime gameTime, MouseState mouse)
        {
            keyNow = Keyboard.GetState(); //keyNow = tecla usada pelo jogador.

            //Dependendo do estado atual de jogo.
            switch (this.stageState)
            {
                //No caso gameplay.
                case StageState.gameplay:
                    StageGravity(); //Gravidade da fase.
                    cleber.Movement(WIDTH, HEIGHT, vilao, keyNow); //Movimentos do personagem.
                    cleber.Shot(bullet, keyNow); //Tiro do personagem.
                    cleber.RemoveBullets(background, background); //Remove os tiros do cleber.
                    vilao.Movement(WIDTH, HEIGHT, cleber, keyNow); //Movimentos do inimigo.
                    vilao.Shot(bullet); //Tiro do vilao.
                    vilao.RemoveBullets(background, background); //Remove os tiros do vilao.
                    InteracaoBullets(cleber, vilao);
                    //LifeBar do personagem será modificada pela sua life.
                    cleberLifeBar.rectanglePicture.Width = cleber.life * 2;
                    //LifeBar do inimigo será modificada pela sua life.
                    vilaoLifeBar.rectanglePicture.Width = vilao.life * 2;
                    //Se a vida de cleber acabar, então o jogador perdeu.
                    if (cleber.life <= 0)
                        stageState = StageState.youlose;
                    //Se a vida do vilao acabar, então o jogador venceu.
                    if (vilao.life <= 0)
                        stageState = StageState.youwin;
                    //Se a tecla enter for pressionada, então entra em pause.
                    if (keyNow.IsKeyDown(Keys.Enter) && keyNow != keyBefore)
                        stageState = StageState.pause;

                    if (cleber.combatState == Character.CombatState.damage)
                    {
                        cleber.life -= 5;
                        cleber.combatState = Character.CombatState.stand;
                    }
                    if (vilao.combatState == Enemy.CombatState.damage)
                    {
                        vilao.life -= 5;
                        vilao.combatState = Enemy.CombatState.stand;
                        vilaoLifeBar.rectanglePicture.X += 10;
                    }


                    break;
                //No caso pause.
                case StageState.pause:
                    if (keyNow.IsKeyDown(Keys.Enter) && keyNow != keyBefore)
                        stageState = StageState.gameplay;
                    break;
                //No caso you win.
                case StageState.youwin:
                    StageGravity(); //Gravidade da fase.
                    if (keyNow.IsKeyDown(Keys.Enter) && keyNow != keyBefore)
                        nextState = GameState.Credits;
                    break;
                //No caso you lose.
                case StageState.youlose:
                    StageGravity(); //Gravidade da fase.
                    if (keyNow.IsKeyDown(Keys.Enter) && keyNow != keyBefore)
                        nextState = GameState.Menu;
                    break;
            }

            keyBefore = keyNow; //Tecla anterior = tecla atual.
        }

        public void Draw(SpriteBatch spriteBatch, MouseState mouse)
        {

            //Desenhamos o background com a textura, a posição e o tamanho definido na classe.
            spriteBatch.Draw(background.texture, background.rectanglePicture, Color.White);
            //Desenhamos a plataforma com a textura, a posição e o tamanho definido na classe.
            spriteBatch.Draw(maskPlataform.texture, maskPlataform.rectanglePicture, Color.White);
            //Desenhamos o avatar do cleber com a textura, a posição e o tamanho definido na classe.
            spriteBatch.Draw(cleberAvatar.texture, cleberAvatar.rectanglePicture, Color.White);
            //Desenhamos o avatar do vilao com a textura, a posição e o tamanho definido na classe.
            spriteBatch.Draw(vilaoAvatar.texture, vilaoAvatar.rectanglePicture, new Rectangle(0, 0, 105, 84), Color.White,
                        0f, Vector2.Zero, SpriteEffects.FlipHorizontally, 0f);
            //Desenhamos o lifebar do cleber com a textura, a posição e o tamanho definido na classe.
            spriteBatch.Draw(cleberLifeBar.texture, cleberLifeBar.rectanglePicture, Color.White);
            //Desenhamos o lifebar do vilao com a textura, a posição e o tamanho definido na classe.
            spriteBatch.Draw(vilaoLifeBar.texture, vilaoLifeBar.rectanglePicture, Color.White);
            //Codigo que depende da direção que o inimigo estiver virado.
            switch (vilao.directionFace)
            {
                //No caso da direção que o vilao deve estar virado for direita.
                case Enemy.DirectionFace.right:
                    //Desenhamos o personagem.
                    spriteBatch.Draw(vilao.texture, vilao.rectanglePicture, vilao.rectangleSprites, Color.White);
                    break;
                //No caso da direção que o vilao deve estar virado for esquerda. Obs: neste caso usamos um efeito que gira a imaguem horizontalmente.
                case Enemy.DirectionFace.left:
                    //Desenhamos o personagem.
                    spriteBatch.Draw(vilao.texture, vilao.rectanglePicture, vilao.rectangleSprites, Color.White,
                        0f, Vector2.Zero, SpriteEffects.FlipHorizontally, 0f);
                    break;
            }
            //Codigo que depende da direção que o personagem estiver virado.
            switch (cleber.directionFace)
            {
                //No caso da direção que o cleber deve estar virado for direita.
                case Character.DirectionFace.right:
                    //Desenhamos o personagem.
                    spriteBatch.Draw(cleber.texture, cleber.rectanglePicture, cleber.rectangleSprites, Color.White);
                    break;
                //No caso da direção que o cleber deve estar virado for esquerda. Obs: neste caso usamos um efeito que gira a imaguem horizontalmente.
                case Character.DirectionFace.left:
                    //Desenhamos o personagem.
                    spriteBatch.Draw(cleber.texture, cleber.rectanglePicture, cleber.rectangleSprites, Color.White,
                        0f, Vector2.Zero, SpriteEffects.FlipHorizontally, 0f);
                    break;
            }
            //Desenhamos os tiros que vão para a direita.
            foreach (Bullet n in cleber.bulletlistRight)
                spriteBatch.Draw(n.texture, n.rectanglePicture, Color.White);
            //Desenhamos os tiros que vão para a esquerda.
            foreach (Bullet n in cleber.bulletlistLeft)
                spriteBatch.Draw(n.texture, n.rectanglePicture, new Rectangle(0, 0, 70, 25), Color.White,
                    0f, Vector2.Zero, SpriteEffects.FlipHorizontally, 0f);

            //Desenhamos os tiros que vão para a direita.
            foreach (Bullet n in vilao.bulletlistRight)
                spriteBatch.Draw(n.texture, n.rectanglePicture, Color.White);
            //Desenhamos os tiros que vão para a esquerda.
            foreach (Bullet n in vilao.bulletlistLeft)
                spriteBatch.Draw(n.texture, n.rectanglePicture, new Rectangle(0, 0, 70, 25), Color.White,
                    0f, Vector2.Zero, SpriteEffects.FlipHorizontally, 0f);

            //Dependendo do estado atual de jogo.
            switch (this.stageState)
            {
                //No caso gameplay.
                case StageState.gameplay:
                    break;
                //No caso pause.
                case StageState.pause:
                    //Desenhamos a tela de pause.
                    spriteBatch.Draw(pauseScreen.texture, pauseScreen.rectanglePicture, Color.White);
                    break;
                //No caso you win.
                case StageState.youwin:
                    //Desenhamos a tela de vitória.
                    spriteBatch.Draw(winScreen.texture, winScreen.rectanglePicture, Color.White);
                    break;
                //No caso you lose.
                case StageState.youlose:
                    //Desenhamos a tela de derrota.
                    spriteBatch.Draw(loseScreen.texture, loseScreen.rectanglePicture, Color.White);
                    break;
            }

        }

        //Metodo da gravidade atuante na fase.
        private void StageGravity()
        {
            //Gravidade para cleber.
            if ((cleber.Colision(colisionPlataform.rectanglePicture, colisionPlataform.mapColor)) && //Se o personagem estiver colidindo com a plataforma E
                         (cleber.rectanglePicture.Bottom < colisionPlataform.rectanglePicture.Top + 20)) //se a parte de baixo do personagem for menor que a parte de cima da plataforma + 20(taxa de erro).
            {
                cleber.gravity.Y = 0; //Então a gravidade atuante no personagem será 0.
                cleber.jumpAble = true; //Ele pode pular.
            }
            else
            {
                cleber.gravity.Y = 10; //Senão a gravidade atuante no personagem será 10.
                cleber.jumpAble = false; //Ele não pode pular.
            }
            //A posição Y do personagem é aumentada de acordo com a gravidade atuante no mesmo.
            cleber.rectanglePicture.Y += (int)cleber.gravity.Y;

            //Gravidade para vilao.
            if ((vilao.Colision(colisionPlataform.rectanglePicture, colisionPlataform.mapColor)) && //Se o inimigo estiver colidindo com a plataforma E
                         (vilao.rectanglePicture.Bottom < colisionPlataform.rectanglePicture.Top + 20)) //se a parte de baixo do inimigo for menor que a parte de cima da plataforma + 20(taxa de erro).
            {
                vilao.gravity.Y = 0; //Então a gravidade atuante no inimigo será 0.
                vilao.jumpAble = true; //Ele pode pular.
            }
            else
            {
                vilao.gravity.Y = 10; //Senão a gravidade atuante no inimigo será 10.
                vilao.jumpAble = false; //Ele não pode pular.
            }
            //A posição Y do inimigo é aumentada de acordo com a gravidade atuante no mesmo.
            vilao.rectanglePicture.Y += (int)vilao.gravity.Y;
        }

        //Metodo de interação dos projeteis.
        private void InteracaoBullets(Character character, Enemy enemy)
        {
            #region DamageInCharacter

            if (character.combatState == Character.CombatState.stand)
            {
                //Metodo com bullets para a direita.
                for (int y = 0; y < enemy.bulletlistRight.Count; y++)
                {
                    //Criamos uma bool para remoção de bullets e definimos ela como falsa.
                    bool removebullet = false;
                    //Se algum bullet colidir com algo.
                    if (enemy.bulletlistRight[y].GetBounding().Intersects(character.GetBounding()))
                    {
                        character.combatState = Character.CombatState.damage;
                        removebullet = true; //Definimos o removebullet como verdadeiro.
                    }
                    //Se removebullet = verdadeiro.
                    if (removebullet)
                        enemy.bulletlistRight.RemoveAt(y); //Removemos o bullet que acertou.
                }
                //Metodo com bullets para a esquerda.
                for (int y = 0; y < enemy.bulletlistLeft.Count; y++)
                {
                    //Criamos uma bool para remoção de bullets e definimos ela como falsa.
                    bool removebullet = false;
                    //Se algum bullet colidir com algo.
                    if (enemy.bulletlistLeft[y].GetBounding().Intersects(character.GetBounding()))
                    {
                        character.combatState = Character.CombatState.damage;
                        removebullet = true; //Definimos o removebullet como verdadeiro.
                    }
                    //Se removebullet = verdadeiro.
                    if (removebullet)
                        enemy.bulletlistLeft.RemoveAt(y); //Removemos o bullet que acertou.
                }
            }

            #endregion

            #region DamageInEnemy

            if (enemy.combatState == Enemy.CombatState.stand)
            {
                //Metodo com bullets para a direita.
                for (int y = 0; y < character.bulletlistRight.Count; y++)
                {
                    //Criamos uma bool para remoção de bullets e definimos ela como falsa.
                    bool removebullet = false;
                    //Se algum bullet colidir com algo.
                    if (character.bulletlistRight[y].GetBounding().Intersects(enemy.GetBounding()))
                    {
                        enemy.combatState = Enemy.CombatState.damage;
                        removebullet = true; //Definimos o removebullet como verdadeiro.
                    }
                    //Se removebullet = verdadeiro.
                    if (removebullet)
                        character.bulletlistRight.RemoveAt(y); //Removemos o bullet que acertou.
                }
                //Metodo com bullets para a esquerda.
                for (int y = 0; y < character.bulletlistLeft.Count; y++)
                {
                    //Criamos uma bool para remoção de bullets e definimos ela como falsa.
                    bool removebullet = false;
                    //Se algum bullet colidir com algo.
                    if (character.bulletlistLeft[y].GetBounding().Intersects(enemy.GetBounding()))
                    {
                        enemy.combatState = Enemy.CombatState.damage;
                        removebullet = true; //Definimos o removebullet como verdadeiro.
                    }
                    //Se removebullet = verdadeiro.
                    if (removebullet)
                        character.bulletlistLeft.RemoveAt(y); //Removemos o bullet que acertou.
                }
            }

            #endregion

            //#region ImpactInBullets

            ////Metodo com bullets para a direita.
            //for (int y = 0; y < character.bulletlistRight.Count; y++)
            //{
            //    //Criamos uma bool para remoção de bullets e definimos ela como falsa.
            //    bool removebullet = false;
            //    for (int x = 0; x < enemy.bulletlistLeft.Count; x++)
            //    {
            //        //Se algum bullet colidir com algo.
            //        if (character.bulletlistRight[y].GetBounding().Intersects(enemy.bulletlistLeft[x].GetBounding()))
            //            removebullet = true; //Definimos o removebullet como verdadeiro.

            //        //Se removebullet = verdadeiro.
            //        if (removebullet)
            //        {
            //            character.bulletlistRight.RemoveAt(y); //Removemos o bullet que acertou.
            //            enemy.bulletlistLeft.RemoveAt(x);
            //        }
            //    }
            //}
            ////Metodo com bullets para a esquerda.
            //for (int y = 0; y < character.bulletlistLeft.Count; y++)
            //{
            //    //Criamos uma bool para remoção de bullets e definimos ela como falsa.
            //    bool removebullet = false;
            //    for (int x = 0; x < enemy.bulletlistRight.Count; x++)
            //    {
            //        //Se algum bullet colidir com algo.
            //        if (character.bulletlistLeft[y].GetBounding().Intersects(enemy.bulletlistRight[x].GetBounding()))
            //            removebullet = true; //Definimos o removebullet como verdadeiro.

            //        //Se removebullet = verdadeiro.
            //        if (removebullet)
            //        {
            //            character.bulletlistLeft.RemoveAt(y); //Removemos o bullet que acertou o gnat.
            //            enemy.bulletlistRight.RemoveAt(x);
            //        }
            //    }
            //}

            //#endregion

        }

    }
}
